import { 
  AmbientLight,
  AnimationAction,
  AnimationMixer,
  BoxGeometry,
  ClampToEdgeWrapping,
  Clock,
  IcosahedronGeometry,
  Mesh,
  MeshLambertMaterial,
  MeshStandardMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  RepeatWrapping,
  Scene, 
  SphereGeometry, 
  SpotLight, 
  SpotLightHelper, 
  Texture, 
  TextureLoader, 
  WebGLRenderer
} from "three";
import stats from '../utils/stats';
// 调用
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GUI } from 'dat.gui';

let clock = new Clock();
let scene = new Scene();
let renderer = setRenderer();
let camera = setCamera();
let mixer: AnimationMixer;

setLight();
init();

const trackballControls = new OrbitControls(camera, renderer.domElement);
// 调整场景位置
trackballControls.target.set(0, 3, 0);

render();

function render() {
  stats.update();
  trackballControls.update();

  if (mixer) {
    mixer.update(clock.getDelta())
  }

  requestAnimationFrame(render);
  renderer.render(scene, camera);
}

function setRenderer() {
  const renderer = new WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 支持阴影生成 
  renderer.shadowMap.enabled = true;
  document.body.appendChild(renderer.domElement);

  return renderer
}

function setCamera(): PerspectiveCamera {
  let camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
  camera.position.set(0, 20, 40);
  scene.add( camera );

  return camera;
}

// 灯光设置
function setLight() {
  scene.add(new AmbientLight(0x444444));
  scene.add(new AmbientLight(0x343434));
  
  let spotLight = new SpotLight(0xffffff);
  spotLight.position.set(-10, 30, 40);
  spotLight.shadow.mapSize.width = 2048;
  spotLight.shadow.mapSize.height = 2048;
  spotLight.shadow.camera.fov = 15;
  spotLight.decay =2;
  spotLight.penumbra = 0.05;
  spotLight.castShadow = true;

  scene.add(spotLight);
  // scene.add(new SpotLightHelper(spotLight));
}

/** 功能区 */
function init() {
  let canvas = createCanvas();

  let textureLoader = new TextureLoader();

  let planeGeom = new PlaneGeometry(60, 40, 1, 1);
  let planeMate = new MeshLambertMaterial({color: 0xffffff});
  const plane = new Mesh(planeGeom, planeMate);
  plane.receiveShadow = true;
  plane.rotation.x = -Math.PI / 2;
  scene.add(plane);

  // 多面几何体
  let polyhedron = new IcosahedronGeometry(8, 0);
  let polyhedronMate = new MeshStandardMaterial({
    metalness: 0.2,
    roughness: 0.7,
    map: textureLoader.load('/textures/general/metal-rust.jpg')
  });
  let polyhedronMesh = new Mesh(polyhedron, polyhedronMate);
  polyhedronMesh.castShadow = true;
  polyhedronMesh.position.x = 20;
  polyhedronMesh.position.y = 7;
  scene.add(polyhedronMesh);

  // 将 canvas 作为凹凸纹理
  let sphereGeom = new SphereGeometry(5, 20, 20);
  let sphereMate = new MeshStandardMaterial({
    metalness: 0,
    roughness: 1,
    map: textureLoader.load('/textures/general/wood-2.jpg'),
    // 用于创建凹凸贴图的纹理
    bumpMap: new Texture(canvas),
    bumpScale: 3,
  });
  let sphereMesh = new Mesh(sphereGeom, sphereMate);
  sphereMesh.position.y = 5;
  sphereMesh.castShadow = true;
  // 注意不更新无法出现效果
  (<Texture>sphereMesh.material.bumpMap).needsUpdate = true;
  scene.add(sphereMesh);

  // 将 canvas 作为纹理
  let cubeGeom = new BoxGeometry(10, 10, 10);
  let cubeMate = new MeshStandardMaterial({
    map: new Texture(canvas),
  });
  let cubeMesh = new Mesh(cubeGeom, cubeMate);
  cubeMesh.position.x = -20;
  cubeMesh.position.y = 5;
  cubeMesh.castShadow = true;
  // 注意不更新无法出现效果
  (<Texture>cubeMesh.material.map).needsUpdate = true;
  scene.add(cubeMesh);

  addGUI([polyhedronMate, sphereMate, cubeMate])
}

function addGUI(materials: any[]): void {
  const controls = {
    x: 1,
    y: 1,
  }
  const gui = new GUI();
  gui.add(controls, 'x', -4, 4).name('X').onChange(val => {
    materials.forEach(mate => {
      mate.map.repeat.set(val, controls.y);
      mate.map.wrapS = RepeatWrapping;
      mate.map.wrapT = RepeatWrapping;
      mate.map.needsUpdate = true;
    });
  });
  gui.add(controls, 'y', -4, 4).name('Y').onChange(val => {
    materials.forEach(mate => {
      // 设置重复次数
      mate.map.repeat.set(val, controls.y);
      // 定义纹理沿 x 轴方向的行为
      // - RepeatWrapping 允许纹理重复自己
      // - ClampToEdgeWrapping 拉伸纹理，填充空间。默认选项。
      mate.map.wrapS = RepeatWrapping;
      // 定义纹理沿 y 轴方向的行为
      mate.map.wrapT = RepeatWrapping;
      // 明确更新纹理
      mate.map.needsUpdate = true;
    });
  });
}

function createCanvas() {
  let canvas = document.createElement('canvas');
  canvas.height = 256
  canvas.width = 256
  canvas.style.position = 'absolute'
  canvas.style.bottom = '0px'
  canvas.style.left = '0px'

  let ctx = (canvas.getContext('2d') as CanvasRenderingContext2D);

  ctx.fillStyle = '#ffffff';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  
  ctx.beginPath();
  ctx.arc(95, 120, 40, 0, 2* Math.PI);
  ctx.stroke();

  document.body.appendChild(canvas);

  return canvas
}